home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / x2ftp / msdos / source / dakit / gio.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-10-10  |  5.5 KB  |  198 lines

  1. /*--gio.c-----------------------------------------------------------------
  2.  * Buffered i/o.
  3.  */
  4.  
  5. #include "main.h"
  6. #include <io.h>
  7. #include <stdio.h>
  8.  
  9. #define    local static
  10.  
  11. /* --- Segment of optional buffer for speeding-up i/o. */
  12. local UWORD ioBufferSeg = NULL;
  13. local UWORD ioBufSize = 0, ioBufNext, ioBufLimit;
  14. local BOOL ioWriting;
  15.  
  16. /* ---------- OpenIOBuffer ---------- */
  17. void OpenIOBuffer(BOOL forWriting)
  18. {
  19.     register WORD bufSize;
  20.     auto WORD tempSeg;
  21.  
  22.     ioWriting = forWriting;
  23.  
  24.     /* --- Allocate i/o buffer. */
  25.     if (ioBufferSeg == NULL) {
  26.         for (bufSize = 16 * 1024; bufSize >= 512; bufSize >>= 1) {
  27.             ioBufferSeg = DAlloc(bufSize);
  28.             if (ioBufferSeg) {
  29.                 /* --- Leave at least 4 KB free for other uses. */
  30.                 tempSeg = DAlloc(4096);
  31.                 if (tempSeg) {
  32.                     tempSeg = SFree(tempSeg);
  33.                     break;        /* Success; leave loop. */
  34.                 } else
  35.                     ioBufferSeg = SFree(ioBufferSeg);
  36.             }
  37.         }
  38.         if (ioBufferSeg != NULL)
  39.             ioBufSize = bufSize;
  40.     }
  41.     ioBufNext = ioBufLimit = 0;
  42.         /* Reading: When next==limit, buffer is empty.
  43.          * Writing: When next== 0, buffer is empty.
  44.          */
  45. }
  46.  
  47. /* ---------- CloseIOBuffer -----------------
  48.  * Writing: flush any remaining data to file.
  49.  * Free the i/o buffer.  Do this whenever finish i/o, so RAM not tied up.
  50.  */
  51. void CloseIOBuffer(WORD file)
  52. {
  53.     if (ioWriting)
  54.         GFlush(file);    /* TBD: ignoring error. */
  55.     ioBufferSeg = SFree(ioBufferSeg);
  56.     ioBufSize = 0;
  57. }
  58.  
  59. /* ---------- GRead ---------------------------------------------
  60.  * Like DOS "read" function, RETURNS # bytes read, or 0 at EOF,
  61.  * or -1 at error.
  62.  */
  63. WORD GRead(WORD file, UBYTE *buffer, UWORD nBytes)
  64. {
  65.     UWORD nRemaining, nAvail, nThisTime;
  66.  
  67.     if (ioBufferSeg) {
  68.         nAvail = ioBufLimit - ioBufNext;
  69.         if (!nAvail && nBytes >= ioBufSize)
  70.             goto readDirectly;    /* More efficient to read buffer directly. */
  71.  
  72.         /* --- Remaining # bytes that need reading. */
  73.         for (nRemaining = nBytes;  nRemaining;  nRemaining -= nThisTime) {
  74.             if (!nAvail) {
  75.                 ioBufLimit = nAvail =
  76.                     readdos(file, ioBufferSeg, 0, ioBufSize);
  77.                 if (nAvail == 0xffff || nAvail == 0) {
  78.                     ioBufLimit = 0;
  79.                     return (nAvail);
  80.                 }
  81.                 ioBufNext = 0;
  82.             }
  83.             nThisTime = MIN(nRemaining, nAvail);
  84.             far_movmem(ioBufferSeg, ioBufNext,
  85.                        dataseg(), (UWORD)buffer,
  86.                        (UWORD)nThisTime);
  87.             buffer += nThisTime;
  88.             ioBufNext += nThisTime;
  89.             nAvail -= nThisTime;
  90.         }
  91.         return (nBytes);
  92.     } else                        /* No ioBuf */
  93. readDirectly:
  94.         return (read(file, buffer, nBytes));
  95. }
  96.  
  97. /* --------------- GReadOne --------------------------------
  98.  * Like "GRead", but read a single byte, with less overhead.
  99.  */
  100. WORD GReadOne(WORD file, UBYTE *buffer)
  101. {
  102.     if (!ioBufferSeg || ioBufLimit == ioBufNext)
  103.         return GRead(file, buffer, 1);
  104.  
  105.     *buffer = *BYTE_FAR_PTR(ioBufferSeg, ioBufNext);
  106.     ioBufNext++;
  107.     return (1);
  108. }
  109.  
  110. /* ---------- GFlush ------------------------------
  111.  * Write out any bytes remaining in the buffer.
  112.  * Return what writedos does, or 0 if nothing to do.
  113.  */
  114. WORD GFlush(WORD file)
  115. {
  116.     auto WORD result = 0;
  117.  
  118.     if (ioBufferSeg && ioBufNext && ioWriting) {
  119.         result = writedos(file, ioBufferSeg, 0, ioBufNext);
  120.         if (result < ioBufNext)
  121.             result = -1;    /* Disk must be full, turn it into an error. */
  122.         ioBufNext = 0;        /* Writing: buffer is empty. */
  123.     }
  124.     return (result);
  125. }
  126.  
  127. /* ---------- GSeek ----------------------------------------------------
  128.  * When reading, ASSUMES seeking forwards.
  129.  * When writing, flush buffer and use lseek.
  130.  * RETURNS 0 if succeeded in seeking w/i buffer.  DIFFERENT THAN LSEEK.
  131.  */
  132. LONG GSeek(WORD file, LONG count, WORD seekType)
  133. {
  134.     UWORD nAvail;
  135.  
  136.     if (ioBufferSeg) {
  137.         if (ioWriting && ioBufNext) {
  138.             GFlush(file);        /* TBD: Ignoring error code. */
  139.             goto seekDirectly;
  140.         }
  141.         nAvail = ioBufLimit - ioBufNext;
  142.  
  143.         if (seekType != SEEK_CUR) {        /* Check for absolute positioning */
  144.             goto emptyAndSeekDirectly;
  145.         }
  146.         if (count > nAvail) {
  147.             count -= nAvail;   /* Adjust seek for bytes already read ahead. */
  148. emptyAndSeekDirectly:
  149.             ioBufNext = ioBufLimit;        /* Reading: buffer is empty. */
  150.             goto seekDirectly;
  151.         }
  152.         ioBufNext += (UWORD)count;        /* Seek within the buffer. */
  153.         return (0);                /* DIFFERENT THAN LSEEK */
  154.     } else
  155. seekDirectly:
  156.         return lseek(file, count, seekType);
  157. }
  158.  
  159. /* ---------- GWrite ---------------------------------------------
  160.  * Like DOS "write" function, RETURNS # bytes written, or -1 at error.
  161.  * DIFFERENCE: if can't write them all, returns -1 instead of # written,
  162.  * UNLESS "writeDirectly", which just uses write().
  163.  */
  164. WORD GWrite(WORD file, UBYTE * buffer, UWORD nBytes)
  165. {
  166.     UWORD nRemaining, nUnused, nThisTime, nWritten;
  167.  
  168.     if (ioBufferSeg) {
  169.         if (!ioBufNext && nBytes >= ioBufSize)
  170.             goto writeDirectly;    /* More efficient to write buffer directly. */
  171.  
  172.         nUnused = ioBufSize - ioBufNext;    /* # bytes unused in buffer. */
  173.  
  174.         /* Remaining # bytes that need writing. */
  175.         for (nRemaining = nBytes; nRemaining; nRemaining -= nThisTime) {
  176.             if (!nUnused) {
  177.                 nWritten = writedos(file, ioBufferSeg, 0, ioBufNext);
  178.                 if (nWritten != ioBufNext) {
  179.                     ioBufNext = 0;        /* Flush the data -- it is lost. */
  180.                     return (-1);        /* ERROR */
  181.                 }
  182.                 ioBufNext = 0;
  183.                 nUnused = ioBufSize;
  184.             }
  185.             nThisTime = MIN(nRemaining, nUnused);
  186.             far_movmem(dataseg(),
  187.                        (UWORD)buffer, ioBufferSeg,
  188.                        ioBufNext, (UWORD)nThisTime);
  189.             buffer += nThisTime;
  190.             ioBufNext += nThisTime;
  191.             nUnused -= nThisTime;
  192.         }
  193.         return (nBytes);        /* OKAY */
  194.     } else                        /* No ioBuf */
  195. writeDirectly:
  196.         return (write(file, buffer, nBytes));
  197. }
  198.